

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#ifndef GPSTK_RINEXOBSID_HPP
#define GPSTK_RINEXOBSID_HPP

/**
 * @file RinexObsID.hpp
 * gpstk::RinexObsID - A specialization of ObsID that has only RINEX-specific
 * observation identifiers.
 */

#include "ObsID.hpp"

namespace gpstk
{
    /// Determine if the given ObsID is valid. If the input string is 3
    /// characters long, the system is unknown and the string is tested with all RINEX
    /// If this string is 4 characters long, the first character is the system
    /// character as described in the Rinex 3 specification.
    bool isValidRinexObsID(const std::string& id);

    /// Determine if the given ObsID is valid, for the given system
    bool isValidRinexObsID(const std::string& id, const char syschar);

    /// class RinexObsID is the set of ObsID's which are valid in RINEX 3.01.
    /// This class simply limits possible values of ObsID, plus a little functionality.
    /// Note it depends critically on map validRinexTrackingCodes, from class ObsID.
    /// This map[sys][freq] = valid codes; e.g.  valid['G'][1]="CSLXPWYMN"
    /// Only exception is there is no pseudorange (C) on GPS L1/L2 N (codeless)
    /// RINEX 3.03 document, section 5.1
    /// sys  freq  code                    ObsID = sys+type+freq+code
    /// GPS   L1   C,S,L,X,P,W,Y,M,N       G CLDS 1 CSLXPWYMN (but not C1N)
    ///       L2   C,D,S,L,X,P,W,Y,M,N     G CLDS 2 CDSLXPWYMN (but not C2N)
    ///       L5   I,Q,X                   G CLDS 5 IQX
    /// GLO   G1   C,P                     R CLDS 1 CP
    ///       G2   C,P                     R CLDS 2 CP
    ///       G3   I,Q,X                   R CLDS 3 IQX
    /// GAL   E1   A,B,C,X,Z               E CLDS 1 ABCXZ
    ///       E5a  I,Q,X                   E CLDS 5 IQX
    ///       E5b  I,Q,X                   E CLDS 7 IQX
    ///       E5ab I,Q,X                   E CLDS 8 IQX
    ///       E6   A,B,C,X,Z               E CLDS 6 ABCXZ
    /// SBAS  L1   C                       S CLDS 1 C
    ///       L5   I,Q,X                   S CLDS 5 IQX
    /// QZSS  L1   C,S,L,X,Z               J CLDS 1 CSLXZ
    ///       L2   S,L,X                   J CLDS 2 SLX
    ///       L5   I,Q,X                   J CLDS 5 IQX
    ///       L6   S,L,X                   J CLDS 6 SLX
    /// BDS   B1   I,Q,X                   C CLDS 2 IQX
    ///       B2   I,Q,X                   C CLDS 7 IQX
    ///       B3   I,Q,X                   C CLDS 6 IQX
    /// IRNSS L5   A,B,C,X                 I CLDS 5 ABCX
    ///       S    A,B,C,X                 I CLDS 9 ABCX
    class RinexObsID : public ObsID
    {
    public:
        /// empty constructor, creates an invalid object
        RinexObsID() : ObsID() {};

        /// Explicit constructior
        RinexObsID(ObservationType ot, CarrierBand cb, TrackingCode tc)
            : ObsID(ot, cb, tc) {};

        /// Construct this object from the string specifier
        RinexObsID(const std::string& strID) noexcept(false);

        /// Constructor from ObsID
        RinexObsID(const ObsID& oid) noexcept(false)
        {
            type=oid.type; band=oid.band; code=oid.code;
            std::string str(this->asString());
            if(!isValidRinexObsID(str))
            {
                InvalidParameter ip("Invalid RinexObsID: " + str);
                GPSTK_THROW(ip);
            }
        }

        /// This returns a representation of this object using the observation
        /// codes described in section 5.1 of the Rinex 3 specification. Note that
        /// this always returns a three character identifier so some information
        /// is lost because some codes are shared between satellite systems.
        std::string asString() const;

        // see ObsID for definition of validRinexTrackingCodes and validRinexSystems.
        //static std::map<char, std::map<char, std::string> > validRinexTrackingCodes;
        // This string contains the system characters for all valid RINEX systems.
        //static std::string validRinexSystems;
        static std::ostream& dumpCheck(std::ostream& s)
            noexcept(false);

    }; // end class RinexObsID

} // namespace gpstk

#endif
